package com.tiancheng.trade.order.controller.open;

import com.tiancheng.trade.commom.core.data.Result;
import com.tiancheng.trade.commom.core.exception.Asserts;
import com.tiancheng.trade.commom.core.exception.error.BusinessErrorInfoEnum;
import com.tiancheng.trade.commom.web.auth.AuthSubjectUtils;
import com.tiancheng.trade.order.bo.CouponBO;
import com.tiancheng.trade.order.bo.OrderBO;
import com.tiancheng.trade.order.bo.SubOrderBO;
import com.tiancheng.trade.order.enums.BusinessTypeEnum;
import com.tiancheng.trade.order.enums.SystemSourceEnum;
import com.tiancheng.trade.order.service.CouponService;
import com.tiancheng.trade.order.service.OpenOrderService;
import com.tiancheng.trade.order.util.CommonUtil;
import com.tiancheng.trade.order.util.ObjectConvertUtil;
import com.tiancheng.trade.order.vo.api.VerificationOrderVO;
import com.tiancheng.trade.order.vo.open.order.*;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: likailun
 * @Description:
 * @Date: create in 2022/3/11 2:42 下午
 */
@RestController
@RequestMapping("/open")
public class OpenController {
    @Resource
    private DiscoveryClient discoveryClient;
    @Resource
    private CouponService couponService;
    @Resource
    private OpenOrderService openOrderService;

    /**
     * 创建订单
     *
     * @param orderVO
     * @return
     */
    @PostMapping(value = "/create", consumes = MediaType.APPLICATION_JSON_VALUE)
    public Result<OpenCreateOrderResVO> create(@RequestBody @Valid OpenCreateOrderBaseVO orderVO) {
        // 生成主订单业务对象
        OrderBO orderBO = this.toOrderBO(orderVO);
        if (StringUtils.isEmpty(orderBO.getSystemSource())) {
            orderBO.setSystemSource(SystemSourceEnum.YOUYUNNAN.getCode());
        }
        if (StringUtils.isEmpty(orderBO.getBusinessType())) {
            orderBO.setBusinessType(BusinessTypeEnum.B2C.getCode());
        }
        // 生成子订单业务对象列表
        List<SubOrderBO> subOrderBOS = this.toSubOrderBO(orderVO);
        // 计算会员折扣金额
        final int vipDiscount = this.getVipDiscount(orderVO);
        // 生成优惠券业务对象
        List<CouponBO> couponBOS = this.toCouponBO(orderVO, vipDiscount);
        // 锁定优惠券信息
        List<CouponBO> lockedCoupons = couponService.lock(couponBOS);
        // 会员优惠
        try {
            // 获取支付渠道
            final OpenCreateOrderResVO openCreateOrderResVO = openOrderService.create(orderBO, subOrderBOS, lockedCoupons);
            return Result.success(openCreateOrderResVO);
        } catch (Exception e) {
            // 创建订单失败，解锁之前的优惠券
            couponService.unlock(lockedCoupons);
            throw e;
        }
    }


    /**
     * 功能描述: 取消订单
     *
     * @param: cancelOrderVO 订单信息
     */
    @PostMapping(value = "/close", consumes = MediaType.APPLICATION_JSON_VALUE)
    public Result closeOrder(@RequestBody @Valid OpenCancelOrderVO cancelOrderVO) {
        int result = openOrderService.cancelOrder(cancelOrderVO);
        if (result == 0) {
            return Result.success();
        } else if (result == 1) {
            return Result.fail(BusinessErrorInfoEnum.ORDER_PAID_REFUSE.getCode(), BusinessErrorInfoEnum.ORDER_PAID_REFUSE.getMessage());
        } else {
            return Result.fail("关闭失败订单，请稍后重试！");
        }
    }

    /**
     * 查询订单明细
     *
     * @param openQueryOrderInfoReqVO 查询参数
     * @return
     */
    @PostMapping(value = "/orderInfo", consumes = MediaType.APPLICATION_JSON_VALUE)
    public Result<OpenQueryOrderInfoResVo> queryOrderInfo(@RequestBody @Valid OpenQueryOrderInfoReqVO openQueryOrderInfoReqVO) {
        OpenQueryOrderInfoResVo order = openOrderService.queryOrderInfo(openQueryOrderInfoReqVO);
        return Result.success(order);
    }

    /**
     * 初始化收银台
     *
     * @param cashierVO
     * @return
     */
    @PostMapping(value = "/cashier", consumes = MediaType.APPLICATION_JSON_VALUE)
    public Result<OpenCashierResVO> cashier(@RequestBody @Valid OpenCashierVO cashierVO) {
        final OpenCashierResVO cashierResVO = openOrderService.cashier(cashierVO);
        return Result.success(cashierResVO);
    }

    /**
     * 初始化收银台页面
     *
     * @param initCashierVO
     * @return
     */
    @PostMapping(value = "/initCashier", consumes = MediaType.APPLICATION_JSON_VALUE)
    public Result<OpenInitCashierResVO> initCashier(@RequestBody @Valid OpenInitCashierVO initCashierVO) {
        final OpenInitCashierResVO openInitCashierResVO = openOrderService.initCashier(initCashierVO);
        return Result.success(openInitCashierResVO);
    }

    /**
     * 支付
     *
     * @param orderPayVO
     * @return
     */
    @PostMapping(value = "/pay", consumes = MediaType.APPLICATION_JSON_VALUE)
    public Result pay(@RequestBody @Valid OpenOrderPayVO orderPayVO) {
        // 校验订单，不允许批次订单和其他订单一起付款
        return Result.success(openOrderService.pay(orderPayVO));
    }

    /**
     * 退款
     *
     * @return
     */
    @PostMapping(value = "/refund", consumes = MediaType.APPLICATION_JSON_VALUE)
    public Result<OpenRefundCreateResVO> execute(@RequestBody @Valid OpenRefundVO refundVO) {
        OpenRefundCreateResVO resVO = openOrderService.refund(refundVO);
        return Result.success(resVO);
    }

    /**
     * 核销订单
     *
     * @return
     */
    @PostMapping("/verification")
    public Result<OpenVerificationResVO> verification(@RequestBody VerificationOrderVO date) {
        return Result.success(openOrderService.verification(date));
    }


    /**
     * 参数转成主订单业务对象
     *
     * @param orderVO
     * @return
     */
    private OrderBO toOrderBO(OpenCreateOrderBaseVO orderVO) {
        BusinessErrorInfoEnum.SYSTEM_ERROR.assertIsTrue(CollectionUtils.isEmpty(orderVO.getCoupons()));
        OrderBO orderBO = ObjectConvertUtil.convert(orderVO, OrderBO.class).get();
        orderBO.setIsTest(Objects.isNull(orderVO.getIsTest()) ? 0 : 1);
        orderBO.setOrderAmount(orderVO.getSubOrders().stream().mapToInt(OpenCreateSubOrderVO::getSubOrderAmount).sum());
        orderBO.setIsCoupon(CollectionUtils.isNotEmpty(orderVO.getCoupons()) ? 1 : 0);
        orderBO.setDiscount(0);
        orderBO.setPlatformDiscount(0);
        if (StringUtils.isEmpty(orderBO.getOriginalOrderId())) {
            orderBO.setOriginalOrderId("0");
        }
        // 默认使用第一笔子订单的商品名称作为订单名称
        if (StringUtils.isEmpty(orderBO.getOrderName())) {
            orderBO.setOrderName(orderVO.getSubOrders().get(0).getProductName());
        }
        // 对orderName进行制表符、换行符、前后空格处理
        orderBO.setOrderName(CommonUtil.trim(orderBO.getOrderName()));
        return orderBO;
    }


    /**
     * 参数转成子订单业务对象
     *
     * @param orderVO
     * @return
     */
    private List<SubOrderBO> toSubOrderBO(OpenCreateOrderBaseVO orderVO) {
        List<SubOrderBO> subOrderBOS = orderVO.getSubOrders().stream().map(subOrderVO -> {
            if (Objects.nonNull(subOrderVO.getProductCount()) && Objects.nonNull(subOrderVO.getUnitPrice())) {
                // 如果单价和数量不为空，校验：subOrderAmount=productCount*unitPrice
                Asserts.isTrue(subOrderVO.getSubOrderAmount().equals(subOrderVO.getProductCount() * subOrderVO.getUnitPrice()), "子订单金额校验失败，子订单金额 = 商品单价 * 数量！");
            }
            SubOrderBO subOrderBO = ObjectConvertUtil.convert(subOrderVO, SubOrderBO.class).get();
            subOrderBO.setOrderId(orderVO.getOrderId());
            subOrderBO.setOrderSource(orderVO.getOrderSource());
            subOrderBO.setCreateTime(orderVO.getCreateTime());
            subOrderBO.setIsCoupon(CollectionUtils.isNotEmpty(orderVO.getCoupons()) ? 1 : 0);
            subOrderBO.setDiscount(0);    //初始化
            subOrderBO.setPlatformDiscount(0);
            // 对名称进行制表符、换行符、前后空格处理
            subOrderBO.setProductName(CommonUtil.trim(subOrderBO.getProductName()));
            subOrderBO.setProductDetail(CommonUtil.trim(subOrderBO.getProductDetail()));
            if (StringUtils.isEmpty(subOrderBO.getOriginalSubOrderId())) {
                subOrderBO.setOriginalSubOrderId("0");
            }
            return subOrderBO;
        }).collect(Collectors.toList());
        return subOrderBOS;
    }

    /**
     * 参数转成优惠券对象（目前只支持平台单张优惠）
     *
     * @param orderVO
     * @param vipDiscount 会员折扣金额
     * @return
     */
    private List<CouponBO> toCouponBO(OpenCreateOrderBaseVO orderVO, int vipDiscount) {
        List<CouponBO> couponBOS = new ArrayList<>();
        if (orderVO.getCoupons() != null && orderVO.getCoupons().size() > 0) {
            couponBOS.addAll(orderVO.getCoupons().stream().map(couponVO -> {
                CouponBO couponBO = new CouponBO();
                couponBO.setCouponCode(couponVO.getCodeId());
                couponBO.setOrderId(orderVO.getOrderId());
                couponBO.setAmount(orderVO.getSubOrders().stream().mapToInt(OpenCreateSubOrderVO::getSubOrderAmount).sum() - vipDiscount);
                couponBO.setProductCode(orderVO.getSubOrders().get(0).getProductCode());
                couponBO.setDiscountSource(orderVO.getOrderSource());
                couponBO.setUid(orderVO.getUid());
                return couponBO;
            }).collect(Collectors.toList()));
        }
        return couponBOS;
    }

    /**
     * 计算折扣金额
     *
     * @return
     */
    private int getVipDiscount(OpenCreateOrderBaseVO orderVO) {
        /*if (null != orderVO.getVipInfo() && orderVO.getVipInfo().getDiscount() != null && orderVO.getVipInfo().getDiscount() > 0 && orderVO.getVipInfo().getDiscount() < 100) {
            int totalAmount = orderVO.getSubOrders().stream().mapToInt(SubOrderVO::getSubOrderAmount).sum();
            final int orderAmount = new BigDecimal(totalAmount).multiply(
                    new BigDecimal(orderVO.getVipInfo().getDiscount()).divide(new BigDecimal(100))
            ).setScale(0, RoundingMode.HALF_UP).intValue();
            return totalAmount - orderAmount;
        }*/
        return 0;
    }

}
